home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / programming / emacs-complete / fsf / emacs / lwlib / lwlib-xm.c < prev    next >
C/C++ Source or Header  |  1994-05-09  |  42KB  |  1,496 lines

  1. /* The lwlib interface to Motif widgets.
  2.    Copyright (C) 1992 Lucid, Inc.
  3.  
  4. This file is part of the Lucid Widget Library.
  5.  
  6. The Lucid Widget Library is free software; you can redistribute it and/or 
  7. modify it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. The Lucid Widget Library is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Emacs; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include <stdlib.h>
  21. #include <unistd.h>
  22. #include <string.h>
  23. #include <stdio.h>
  24.  
  25. #include <X11/StringDefs.h>
  26. #include <X11/IntrinsicP.h>
  27. #include <X11/ObjectP.h>
  28. #include <X11/CoreP.h>
  29. #include <X11/CompositeP.h>
  30.  
  31. #include "lwlib-Xm.h"
  32. #include "lwlib-utils.h"
  33.  
  34. #include <Xm/BulletinB.h>
  35. #include <Xm/CascadeB.h>
  36. #include <Xm/DrawingA.h>
  37. #include <Xm/FileSB.h>
  38. #include <Xm/Label.h>
  39. #include <Xm/List.h>
  40. #include <Xm/MenuShell.h>
  41. #include <Xm/MessageB.h>
  42. #include <Xm/PushB.h>
  43. #include <Xm/PushBG.h>
  44. #include <Xm/ArrowB.h>
  45. #include <Xm/SelectioB.h>
  46. #include <Xm/Text.h>
  47. #include <Xm/TextF.h>
  48. #include <Xm/ToggleB.h>
  49. #include <Xm/ToggleBG.h>
  50. #include <Xm/RowColumn.h>
  51. #include <Xm/ScrolledW.h>
  52. #include <Xm/Separator.h>
  53. #include <Xm/DialogS.h>
  54. #include <Xm/Form.h>
  55.  
  56. static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
  57. static void xm_internal_update_other_instances (Widget, XtPointer,
  58.                         XtPointer);
  59. static void xm_generic_callback (Widget, XtPointer, XtPointer);
  60. static void xm_nosel_callback (Widget, XtPointer, XtPointer);
  61. static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
  62.  
  63. static void
  64. xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
  65.         Boolean deep_p);
  66.  
  67. /* Structures to keep destroyed instances */
  68. typedef struct _destroyed_instance 
  69. {
  70.   char*        name;
  71.   char*        type;
  72.   Widget     widget;
  73.   Widget    parent;
  74.   Boolean    pop_up_p;
  75.   struct _destroyed_instance*    next;
  76. } destroyed_instance;
  77.  
  78. static destroyed_instance*
  79. all_destroyed_instances = NULL;
  80.  
  81. static destroyed_instance*
  82. make_destroyed_instance (char* name, char* type, Widget widget, Widget parent,
  83.              Boolean pop_up_p)
  84. {
  85.   destroyed_instance* instance =
  86.     (destroyed_instance*)malloc (sizeof (destroyed_instance));
  87.   instance->name = safe_strdup (name);
  88.   instance->type = safe_strdup (type);
  89.   instance->widget = widget;
  90.   instance->parent = parent;
  91.   instance->pop_up_p = pop_up_p;
  92.   instance->next = NULL;
  93.   return instance;
  94. }
  95.              
  96. static void
  97. free_destroyed_instance (destroyed_instance* instance)
  98. {
  99.   free (instance->name);
  100.   free (instance->type);
  101.   free (instance);
  102. }
  103.  
  104. /* motif utility functions */
  105. Widget
  106. first_child (Widget widget)
  107. {
  108.   return ((CompositeWidget)widget)->composite.children [0];
  109. }
  110.  
  111. Boolean
  112. lw_motif_widget_p (Widget widget)
  113. {
  114.   return 
  115.     XtClass (widget) == xmDialogShellWidgetClass
  116.       || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
  117. }
  118.  
  119. static XmString
  120. resource_motif_string (Widget widget, char* name)
  121. {
  122.   XtResource resource;
  123.   XmString result = 0;
  124.   
  125.   resource.resource_name = name;
  126.   resource.resource_class = XmCXmString;
  127.   resource.resource_type = XmRXmString;
  128.   resource.resource_size = sizeof (XmString);
  129.   resource.resource_offset = 0;
  130.   resource.default_type = XtRImmediate;
  131.   resource.default_addr = 0;
  132.  
  133.   XtGetSubresources (widget, (XtPointer)&result, "dialogString",
  134.              "DialogString", &resource, 1, NULL, 0);
  135.   return result;
  136. }
  137.  
  138. static void
  139. destroy_all_children (Widget widget)
  140. {
  141.   Widget* children;
  142.   unsigned int number;
  143.   int i;
  144.  
  145.   children = XtCompositeChildren (widget, &number);
  146.   if (children)
  147.     {
  148.       /* Unmanage all children and destroy them.  They will only be 
  149.        * really destroyed when we get out of DispatchEvent. */
  150.       for (i = 0; i < number; i++)
  151.     {
  152.       Widget child = children [i];
  153.       if (!child->core.being_destroyed)
  154.         {
  155.           XtUnmanageChild (child);
  156.           XtDestroyWidget (child);
  157.         }
  158.     }
  159.       XtFree ((char *) children);
  160.     }
  161. }
  162.  
  163. /* update the label of anything subclass of a label */
  164. static void
  165. xm_update_label (widget_instance* instance, Widget widget, widget_value* val)
  166. {
  167.   XmString res_string = 0;
  168.   XmString built_string = 0;
  169.   XmString key_string = 0;
  170.   Arg al [256];
  171.   int ac;
  172.   
  173.   ac = 0;
  174.  
  175.   if (val->value)
  176.     {
  177.       res_string = resource_motif_string (widget, val->value);
  178.  
  179.       if (res_string)
  180.     {
  181.       XtSetArg (al [ac], XmNlabelString, res_string); ac++;
  182.     }
  183.       else
  184.     {
  185.       built_string =
  186.         XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
  187.       XtSetArg (al [ac], XmNlabelString, built_string); ac++;
  188.     }
  189.       XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
  190.     }
  191.   
  192.   if (val->key)
  193.     {
  194.       key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
  195.       XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
  196.     }
  197.  
  198.   if (ac)
  199.     XtSetValues (widget, al, ac);
  200.  
  201.   if (built_string)
  202.     XmStringFree (built_string);
  203.  
  204.   if (key_string)
  205.     XmStringFree (key_string);
  206. }
  207.  
  208. /* update of list */
  209. static void
  210. xm_update_list (widget_instance* instance, Widget widget, widget_value* val)
  211. {
  212.   widget_value* cur;
  213.   int i;
  214.   XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
  215.   XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
  216.          instance);
  217.   for (cur = val->contents, i = 0; cur; cur = cur->next)
  218.     if (cur->value)
  219.       {
  220.     XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
  221.     i += 1;
  222.     XmListAddItem (widget, xmstr, 0);
  223.     if (cur->selected)
  224.       XmListSelectPos (widget, i, False);
  225.     XmStringFree (xmstr);
  226.       }
  227. }
  228.  
  229. /* update of buttons */
  230. static void
  231. xm_update_pushbutton (widget_instance* instance, Widget widget,
  232.               widget_value* val)
  233. {
  234.   XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, 0);
  235.   XtRemoveAllCallbacks (widget, XmNactivateCallback);
  236.   XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
  237. }
  238.  
  239. static void
  240. xm_update_cascadebutton (widget_instance* instance, Widget widget,
  241.              widget_value* val)
  242. {
  243.   /* Should also rebuild the menu by calling ...update_menu... */
  244.   XtRemoveAllCallbacks (widget, XmNcascadingCallback);
  245.   XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
  246.          instance);
  247. }
  248.  
  249. /* update toggle and radiobox */
  250. static void
  251. xm_update_toggle (widget_instance* instance, Widget widget, widget_value* val)
  252. {
  253.   XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
  254.   XtAddCallback (widget, XmNvalueChangedCallback,
  255.          xm_internal_update_other_instances, instance);
  256.   XtVaSetValues (widget, XmNset, val->selected,
  257.          XmNalignment, XmALIGNMENT_BEGINNING, 0);
  258. }
  259.  
  260. static void
  261. xm_update_radiobox (widget_instance* instance, Widget widget,
  262.             widget_value* val)
  263. {
  264.   Widget toggle;
  265.   widget_value* cur;
  266.  
  267.   /* update the callback */
  268.   XtRemoveAllCallbacks (widget, XmNentryCallback);
  269.   XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
  270.  
  271.   /* first update all the toggles */
  272.   /* Energize kernel interface is currently bad.  It sets the selected widget
  273.      with the selected flag but returns it by its name.  So we currently
  274.      have to support both setting the selection with the selected slot
  275.      of val contents and setting it with the "value" slot of val.  The latter
  276.      has a higher priority.  This to be removed when the kernel is fixed. */
  277.   for (cur = val->contents; cur; cur = cur->next)
  278.     {
  279.       toggle = XtNameToWidget (widget, cur->value);
  280.       if (toggle)
  281.     {
  282.       XtVaSetValues (toggle, XmNsensitive, cur->enabled, 0);
  283.       if (!val->value && cur->selected)
  284.         XtVaSetValues (toggle, XmNset, cur->selected, 0);
  285.       if (val->value && strcmp (val->value, cur->value))
  286.         XtVaSetValues (toggle, XmNset, False, 0);
  287.     }
  288.     }
  289.  
  290.   /* The selected was specified by the value slot */
  291.   if (val->value)
  292.     {
  293.       toggle = XtNameToWidget (widget, val->value);
  294.       if (toggle)
  295.     XtVaSetValues (toggle, XmNset, True, 0);
  296.     }
  297. }
  298.  
  299. /* update a popup menu, pulldown menu or a menubar */
  300. static Boolean
  301. all_dashes_p (char* s)
  302. {
  303.   char* t;
  304.   for (t = s; *t; t++)
  305.     if (*t != '-')
  306.       return False;
  307.   return True;
  308. }
  309.  
  310. static void
  311. make_menu_in_widget (widget_instance* instance, Widget widget,
  312.              widget_value* val)
  313. {
  314.   Widget* children = 0;
  315.   int num_children;
  316.   int child_index;
  317.   widget_value* cur;
  318.   Widget button = 0;
  319.   Widget menu;
  320.   Arg al [256];
  321.   int ac;
  322.   Boolean menubar_p;
  323.  
  324.   /* Allocate the children array */
  325.   for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
  326.   children = (Widget*)XtMalloc (num_children * sizeof (Widget));
  327.  
  328.   /* tricky way to know if this RowColumn is a menubar or a pulldown... */
  329.   menubar_p = False;
  330.   XtSetArg (al[0], XmNisHomogeneous, &menubar_p);
  331.   XtGetValues (widget, al, 1);
  332.  
  333.   /* add the unmap callback for popups and pulldowns */
  334.   /*** this sounds bogus ***/
  335.   if (!menubar_p)
  336.     XtAddCallback (XtParent (widget), XmNpopdownCallback,
  337.            xm_pop_down_callback, (XtPointer)instance);
  338.  
  339.   for (child_index = 0, cur = val; cur; child_index++, cur = cur->next)
  340.     {    
  341.       ac = 0;
  342.       XtSetArg (al [ac], XmNsensitive, cur->enabled); ac++;
  343.       XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
  344.       XtSetArg (al [ac], XmNuserData, cur->call_data); ac++;
  345.       
  346.       if (all_dashes_p (cur->name))
  347.     {
  348.       button = XmCreateSeparator (widget, cur->name, NULL, 0);
  349.     }
  350.       else if (!cur->contents)
  351.     {
  352.       if (menubar_p)
  353.         button = XmCreateCascadeButton (widget, cur->name, al, ac);
  354.       else if (!cur->call_data)
  355.         button = XmCreateLabel (widget, cur->name, al, ac);
  356.       else
  357.         button = XmCreatePushButtonGadget (widget, cur->name, al, ac);
  358.  
  359.       xm_update_label (instance, button, cur);
  360.  
  361.       /* don't add a callback to a simple label */
  362.       if (cur->call_data)
  363.         XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
  364.                (XtPointer)instance);
  365.     }
  366.       else
  367.     {
  368.       menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
  369.       make_menu_in_widget (instance, menu, cur->contents);
  370.       XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
  371.       button = XmCreateCascadeButton (widget, cur->name, al, ac);
  372.  
  373.       xm_update_label (instance, button, cur);
  374.  
  375.       XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
  376.              (XtPointer)instance);
  377.     }
  378.  
  379.       children [child_index] = button;
  380.     }
  381.  
  382.   XtManageChildren (children, num_children);
  383.  
  384.   /* Last entry is the help button.  Has to be done after managing
  385.    * the buttons otherwise the menubar is only 4 pixels high... */
  386.   if (button)
  387.     {
  388.       ac = 0;
  389.       XtSetArg (al [ac], XmNmenuHelpWidget, button); ac++;
  390.       XtSetValues (widget, al, ac);
  391.     }
  392.  
  393.   XtFree ((char *) children);
  394. }
  395.  
  396. static void
  397. update_one_menu_entry (widget_instance* instance, Widget widget,
  398.                widget_value* val, Boolean deep_p)
  399. {
  400.   Arg al [256];
  401.   int ac;
  402.   Widget menu;
  403.   widget_value* contents;
  404.  
  405.   if (val->change == NO_CHANGE)
  406.     return;
  407.  
  408.   /* update the sensitivity and userdata */
  409.   /* Common to all widget types */
  410.   XtVaSetValues (widget,
  411.          XmNsensitive, val->enabled,
  412.          XmNuserData, val->call_data,
  413.          0);
  414.  
  415.   /* update the menu button as a label. */
  416.   if (val->change >= VISIBLE_CHANGE)
  417.     xm_update_label (instance, widget, val);
  418.  
  419.   /* update the pulldown/pullaside as needed */
  420.   ac = 0;
  421.   menu = NULL;
  422.   XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
  423.   XtGetValues (widget, al, ac);
  424.   
  425.   contents = val->contents;
  426.  
  427.   if (!menu)
  428.     {
  429.       if (contents)
  430.     {
  431.       menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
  432.       make_menu_in_widget (instance, menu, contents);
  433.       ac = 0;
  434.       XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
  435.       XtSetValues (widget, al, ac);
  436.     }
  437.     }
  438.   else if (!contents)
  439.     {
  440.       ac = 0;
  441.       XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
  442.       XtSetValues (widget, al, ac);
  443.       XtDestroyWidget (menu);
  444.     }
  445.   else if (deep_p && contents->change != NO_CHANGE)
  446.     xm_update_menu (instance, menu, val, 1);
  447. }
  448.  
  449. static void
  450. xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
  451.         Boolean deep_p)
  452. {
  453.   /* Widget is a RowColumn widget whose contents have to be updated
  454.    * to reflect the list of items in val->contents */
  455.   if (val->contents->change == STRUCTURAL_CHANGE)
  456.     {
  457.       destroy_all_children (widget);
  458.       make_menu_in_widget (instance, widget, val->contents);
  459.     }
  460.   else
  461.     {
  462.       /* Update all the buttons of the RowColumn in order. */
  463.       Widget* children;
  464.       unsigned int num_children;
  465.       int i;
  466.       widget_value* cur;
  467.  
  468.       children = XtCompositeChildren (widget, &num_children);
  469.       if (children)
  470.     {
  471.       for (i = 0, cur = val->contents; i < num_children; i++)
  472.         {
  473.           if (!cur)
  474.         abort ();
  475.           if (children [i]->core.being_destroyed
  476.           || strcmp (XtName (children [i]), cur->name))
  477.         continue;
  478.           update_one_menu_entry (instance, children [i], cur, deep_p);
  479.           cur = cur->next;
  480.         }
  481.       XtFree ((char *) children);
  482.     }
  483.       if (cur)
  484.     abort ();
  485.     }
  486. }
  487.  
  488.  
  489. /* update text widgets */
  490.  
  491. static void
  492. xm_update_text (widget_instance* instance, Widget widget, widget_value* val)
  493. {
  494.   XmTextSetString (widget, val->value ? val->value : "");
  495.   XtRemoveAllCallbacks (widget, XmNactivateCallback);
  496.   XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
  497.   XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
  498.   XtAddCallback (widget, XmNvalueChangedCallback,
  499.          xm_internal_update_other_instances, instance);
  500. }
  501.  
  502. static void
  503. xm_update_text_field (widget_instance* instance, Widget widget,
  504.               widget_value* val)
  505. {
  506.   XmTextFieldSetString (widget, val->value ? val->value : "");
  507.   XtRemoveAllCallbacks (widget, XmNactivateCallback);
  508.   XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
  509.   XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
  510.   XtAddCallback (widget, XmNvalueChangedCallback,
  511.          xm_internal_update_other_instances, instance);
  512. }
  513.  
  514.  
  515. /* update a motif widget */
  516.  
  517. void
  518. xm_update_one_widget (widget_instance* instance, Widget widget,
  519.               widget_value* val, Boolean deep_p)
  520. {
  521.   WidgetClass class;
  522.   
  523.   /* Mark as not edited */
  524.   val->edited = False;
  525.  
  526.   /* Common to all widget types */
  527.   XtVaSetValues (widget,
  528.          XmNsensitive, val->enabled,
  529.          XmNuserData, val->call_data,
  530.          0);
  531.   
  532.   /* Common to all label like widgets */
  533.   if (XtIsSubclass (widget, xmLabelWidgetClass))
  534.     xm_update_label (instance, widget, val);
  535.   
  536.   class = XtClass (widget);
  537.   /* Class specific things */
  538.   if (class == xmPushButtonWidgetClass ||
  539.       class == xmArrowButtonWidgetClass)
  540.     {
  541.       xm_update_pushbutton (instance, widget, val);
  542.     }
  543.   else if (class == xmCascadeButtonWidgetClass)
  544.     {
  545.       xm_update_cascadebutton (instance, widget, val);
  546.     }
  547.   else if (class == xmToggleButtonWidgetClass
  548.        || class == xmToggleButtonGadgetClass)
  549.     {
  550.       xm_update_toggle (instance, widget, val);
  551.     }
  552.   else if (class == xmRowColumnWidgetClass)
  553.     {
  554.       Boolean radiobox = 0;
  555.       int ac = 0;
  556.       Arg al [1];
  557.       
  558.       XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
  559.       XtGetValues (widget, al, ac);
  560.       
  561.       if (radiobox)
  562.     xm_update_radiobox (instance, widget, val);
  563.       else
  564.     xm_update_menu (instance, widget, val, deep_p);
  565.     }
  566.   else if (class == xmTextWidgetClass)
  567.     {
  568.       xm_update_text (instance, widget, val);
  569.     }
  570.   else if (class == xmTextFieldWidgetClass)
  571.     {
  572.       xm_update_text_field (instance, widget, val);
  573.     }
  574.   else if (class == xmListWidgetClass)
  575.     {
  576.       xm_update_list (instance, widget, val);
  577.     }
  578. }
  579.  
  580. /* getting the value back */
  581. void
  582. xm_update_one_value (widget_instance* instance, Widget widget,
  583.              widget_value* val)
  584. {
  585.   WidgetClass class = XtClass (widget);
  586.   widget_value *old_wv;
  587.  
  588.   /* copy the call_data slot into the "return" widget_value */
  589.   for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
  590.     if (!strcmp (val->name, old_wv->name))
  591.       {
  592.     val->call_data = old_wv->call_data;
  593.     break;
  594.       }
  595.   
  596.   if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
  597.     {
  598.       XtVaGetValues (widget, XmNset, &val->selected, 0);
  599.       val->edited = True;
  600.     }
  601.   else if (class == xmTextWidgetClass)
  602.     {
  603.       if (val->value)
  604.     free (val->value);
  605.       val->value = XmTextGetString (widget);
  606.       val->edited = True;
  607.     }
  608.   else if (class == xmTextFieldWidgetClass)
  609.     {
  610.       if (val->value)
  611.     free (val->value);
  612.       val->value = XmTextFieldGetString (widget);
  613.       val->edited = True;
  614.     }
  615.   else if (class == xmRowColumnWidgetClass)
  616.     {
  617.       Boolean radiobox = 0;
  618.       int ac = 0;
  619.       Arg al [1];
  620.       
  621.       XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
  622.       XtGetValues (widget, al, ac);
  623.       
  624.       if (radiobox)
  625.     {
  626.       CompositeWidget radio = (CompositeWidget)widget;
  627.       int i;
  628.       for (i = 0; i < radio->composite.num_children; i++)
  629.         {
  630.           int set = False;
  631.           Widget toggle = radio->composite.children [i];
  632.           
  633.           XtVaGetValues (toggle, XmNset, &set, 0);
  634.           if (set)
  635.         {
  636.           if (val->value)
  637.             free (val->value);
  638.           val->value = safe_strdup (XtName (toggle));
  639.         }
  640.         }
  641.       val->edited = True;
  642.     }
  643.     }
  644.   else if (class == xmListWidgetClass)
  645.     {
  646.       int pos_cnt;
  647.       int* pos_list;
  648.       if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
  649.     {
  650.       int i;
  651.       widget_value* cur;
  652.       for (cur = val->contents, i = 0; cur; cur = cur->next)
  653.         if (cur->value)
  654.           {
  655.         int j;
  656.         cur->selected = False;
  657.         i += 1;
  658.         for (j = 0; j < pos_cnt; j++)
  659.           if (pos_list [j] == i)
  660.             {
  661.               cur->selected = True;
  662.               val->value = safe_strdup (cur->name);
  663.             }
  664.           }
  665.       val->edited = 1;
  666.       XtFree ((char *) pos_list);
  667.     }
  668.     }
  669. }
  670.  
  671.  
  672. /* This function is for activating a button from a program.  It's wrong because
  673.    we pass a NULL argument in the call_data which is not Motif compatible.
  674.    This is used from the XmNdefaultAction callback of the List widgets to
  675.    have a dble-click put down a dialog box like the button woudl do. 
  676.    I could not find a way to do that with accelerators.
  677.  */
  678. static void
  679. activate_button (Widget widget, XtPointer closure, XtPointer call_data)
  680. {
  681.   Widget button = (Widget)closure;
  682.   XtCallCallbacks (button, XmNactivateCallback, NULL);
  683. }
  684.  
  685. /* creation functions */
  686.  
  687. /* dialogs */
  688. static Widget
  689. make_dialog (char* name, Widget parent, Boolean pop_up_p,
  690.          char* shell_title, char* icon_name, Boolean text_input_slot,
  691.          Boolean radio_box, Boolean list,
  692.          int left_buttons, int right_buttons)
  693. {
  694.   Widget result;
  695.   Widget form;
  696.   Widget row;
  697.   Widget icon;
  698.   Widget icon_separator;
  699.   Widget message;
  700.   Widget value = 0;
  701.   Widget separator;
  702.   Widget button = 0;
  703.   Widget children [16];        /* for the final XtManageChildren */
  704.   int     n_children;
  705.   Arg     al[64];            /* Arg List */
  706.   int     ac;            /* Arg Count */
  707.   int     i;
  708.   
  709.   if (pop_up_p)
  710.     {
  711.       ac = 0;
  712.       XtSetArg(al[ac], XmNtitle, shell_title); ac++;
  713.       XtSetArg(al[ac], XtNallowShellResize, True); ac++;
  714.       XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
  715.       result = XmCreateDialogShell (parent, "dialog", al, ac);
  716.       ac = 0;
  717.       XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
  718. /*      XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
  719.       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
  720.       form = XmCreateForm (result, shell_title, al, ac);
  721.     }
  722.   else
  723.     {
  724.       ac = 0;
  725.       XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
  726.       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
  727.       form = XmCreateForm (parent, shell_title, al, ac);
  728.       result = form;
  729.     }
  730.  
  731.   ac = 0;
  732.   XtSetArg(al[ac], XmNpacking, XmPACK_COLUMN); ac++;
  733.   XtSetArg(al[ac], XmNorientation, XmVERTICAL); ac++;
  734.   XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
  735.   XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
  736.   XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
  737.   XtSetArg(al[ac], XmNspacing, 13); ac++;
  738.   XtSetArg(al[ac], XmNadjustLast, False); ac++;
  739.   XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
  740.   XtSetArg(al[ac], XmNisAligned, True); ac++;
  741.   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
  742.   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
  743.   XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  744.   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  745.   XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  746.   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  747.   XtSetArg(al[ac], XmNrightOffset, 13); ac++;
  748.   row = XmCreateRowColumn (form, "row", al, ac);
  749.   
  750.   n_children = 0;
  751.   for (i = 0; i < left_buttons; i++)
  752.     {
  753.       char button_name [16];
  754.       sprintf (button_name, "button%d", i + 1);
  755.       ac = 0;
  756.       if (i == 0)
  757.     {
  758.       XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
  759.       XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
  760.     }
  761.       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
  762.       children [n_children] = XmCreatePushButton (row, button_name, al, ac);
  763.  
  764.       if (i == 0)
  765.     {
  766.       button = children [n_children];
  767.       ac = 0;
  768.       XtSetArg(al[ac], XmNdefaultButton, button); ac++;
  769.       XtSetValues (row, al, ac);
  770.     }
  771.  
  772.       n_children++;
  773.     }
  774.  
  775.   /* invisible seperator button */
  776.   ac = 0;
  777.   XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
  778.   children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
  779.   n_children++;
  780.   
  781.   for (i = 0; i < right_buttons; i++)
  782.     {
  783.       char button_name [16];
  784.       sprintf (button_name, "button%d", left_buttons + i + 1);
  785.       ac = 0;
  786.       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
  787.       children [n_children] = XmCreatePushButton (row, button_name, al, ac);
  788.       if (! button) button = children [n_children];
  789.       n_children++;
  790.     }
  791.   
  792.   XtManageChildren (children, n_children);
  793.   
  794.   ac = 0;
  795.   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
  796.   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  797.   XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  798.   XtSetArg(al[ac], XmNbottomWidget, row); ac++;
  799.   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  800.   XtSetArg(al[ac], XmNleftOffset, 0); ac++;
  801.   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  802.   XtSetArg(al[ac], XmNrightOffset, 0); ac++;
  803.   separator = XmCreateSeparator (form, "", al, ac);
  804.  
  805.   ac = 0;
  806.   XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
  807.   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
  808.   XtSetArg(al[ac], XmNtopOffset, 13); ac++;
  809.   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
  810.   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  811.   XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  812.   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
  813.   icon = XmCreateLabel (form, icon_name, al, ac);
  814.  
  815.   ac = 0;
  816.   XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
  817.   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
  818.   XtSetArg(al[ac], XmNtopOffset, 6); ac++;
  819.   XtSetArg(al[ac], XmNtopWidget, icon); ac++;
  820.   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  821.   XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
  822.   XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
  823.   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
  824.   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
  825.   icon_separator = XmCreateLabel (form, "", al, ac);
  826.  
  827.   if (text_input_slot)
  828.     {
  829.       ac = 0;
  830.       XtSetArg(al[ac], XmNcolumns, 50); ac++;
  831.       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
  832.       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  833.       XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  834.       XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
  835.       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
  836.       XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  837.       XtSetArg(al[ac], XmNleftWidget, icon); ac++;
  838.       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  839.       XtSetArg(al[ac], XmNrightOffset, 13); ac++;
  840.       value = XmCreateTextField (form, "value", al, ac);
  841.     }
  842.   else if (radio_box)
  843.     {
  844.       Widget radio_butt;
  845.       ac = 0;
  846.       XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
  847.       XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
  848.       XtSetArg(al[ac], XmNspacing, 13); ac++;
  849.       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
  850.       XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
  851.       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  852.       XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  853.       XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
  854.       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
  855.       XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  856.       XtSetArg(al[ac], XmNleftWidget, icon); ac++;
  857.       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  858.       XtSetArg(al[ac], XmNrightOffset, 13); ac++;
  859.       value = XmCreateRadioBox (form, "radiobutton1", al, ac);
  860.       ac = 0;
  861.       i = 0;
  862.       radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
  863.       children [i++] = radio_butt;
  864.       radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
  865.       children [i++] = radio_butt;
  866.       radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
  867.       children [i++] = radio_butt;
  868.       XtManageChildren (children, i);
  869.     }
  870.   else if (list)
  871.     {
  872.       ac = 0;
  873.       XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
  874.       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
  875.       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  876.       XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  877.       XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
  878.       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
  879.       XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  880.       XtSetArg(al[ac], XmNleftWidget, icon); ac++;
  881.       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  882.       XtSetArg(al[ac], XmNrightOffset, 13); ac++;
  883.       value = XmCreateScrolledList (form, "list", al, ac);
  884.  
  885.       /* this is the easiest way I found to have the dble click in the
  886.      list activate the default button */
  887.       XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
  888.     }
  889.   
  890.   ac = 0;
  891.   XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
  892.   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
  893.   XtSetArg(al[ac], XmNtopOffset, 13); ac++;
  894.   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  895.   XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  896.   XtSetArg(al[ac], XmNbottomWidget,
  897.        text_input_slot || radio_box || list ? value : separator); ac++;
  898.   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
  899.   XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  900.   XtSetArg(al[ac], XmNleftWidget, icon); ac++;
  901.   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  902.   XtSetArg(al[ac], XmNrightOffset, 13); ac++;
  903.   message = XmCreateLabel (form, "message", al, ac);
  904.   
  905.   if (list)
  906.     XtManageChild (value);
  907.  
  908.   i = 0;
  909.   children [i] = row; i++;
  910.   children [i] = separator; i++;
  911.   if (text_input_slot || radio_box)
  912.     {
  913.       children [i] = value; i++;
  914.     }
  915.   children [i] = message; i++;
  916.   children [i] = icon; i++;
  917.   children [i] = icon_separator; i++;
  918.   XtManageChildren (children, i);
  919.   
  920.   if (text_input_slot || list)
  921.     {
  922.       XtInstallAccelerators (value, button);
  923.       XtSetKeyboardFocus (result, value);
  924.     }
  925.   else
  926.     {
  927.       XtInstallAccelerators (form, button);
  928.       XtSetKeyboardFocus (result, button);
  929.     }
  930.   
  931.   return result;
  932. }
  933.  
  934. static destroyed_instance*
  935. find_matching_instance (widget_instance* instance)
  936. {
  937.   destroyed_instance*    cur;
  938.   destroyed_instance*    prev;
  939.   char*    type = instance->info->type;
  940.   char*    name = instance->info->name;
  941.  
  942.   for (prev = NULL, cur = all_destroyed_instances;
  943.        cur;
  944.        prev = cur, cur = cur->next)
  945.     {
  946.       if (!strcmp (cur->name, name)
  947.       && !strcmp (cur->type, type)
  948.       && cur->parent == instance->parent
  949.       && cur->pop_up_p == instance->pop_up_p)
  950.     {
  951.       if (prev)
  952.         prev->next = cur->next;
  953.       else
  954.         all_destroyed_instances = cur->next;
  955.       return cur;
  956.     }
  957.       /* do some cleanup */
  958.       else if (!cur->widget)
  959.     {
  960.       if (prev)
  961.         prev->next = cur->next;
  962.       else
  963.         all_destroyed_instances = cur->next;
  964.       free_destroyed_instance (cur);
  965.       cur = prev ? prev : all_destroyed_instances;
  966.     }
  967.     }
  968.   return NULL;
  969. }
  970.  
  971. static void
  972. mark_dead_instance_destroyed (Widget widget, XtPointer closure,
  973.                   XtPointer call_data)
  974. {
  975.   destroyed_instance* instance = (destroyed_instance*)closure;
  976.   instance->widget = NULL;
  977. }
  978.  
  979. static void
  980. recenter_widget (Widget widget)
  981. {
  982.   Widget parent = XtParent (widget);
  983.   Screen* screen = XtScreen (widget);
  984.   Dimension screen_width = WidthOfScreen (screen);
  985.   Dimension screen_height = HeightOfScreen (screen);
  986.   Dimension parent_width = 0;
  987.   Dimension parent_height = 0;
  988.   Dimension child_width = 0;
  989.   Dimension child_height = 0;
  990.   Position x;
  991.   Position y;
  992.  
  993.   XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, 0);
  994.   XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
  995.          0);
  996.  
  997.   x = (((Position)parent_width) - ((Position)child_width)) / 2;
  998.   y = (((Position)parent_height) - ((Position)child_height)) / 2;
  999.   
  1000.   XtTranslateCoords (parent, x, y, &x, &y);
  1001.  
  1002.   if (x + child_width > screen_width)
  1003.     x = screen_width - child_width;
  1004.   if (x < 0)
  1005.     x = 0;
  1006.  
  1007.   if (y + child_height > screen_height)
  1008.     y = screen_height - child_height;
  1009.   if (y < 0)
  1010.     y = 0;
  1011.  
  1012.   XtVaSetValues (widget, XtNx, x, XtNy, y, 0);
  1013. }
  1014.  
  1015. static Widget
  1016. recycle_instance (destroyed_instance* instance)
  1017. {
  1018.   Widget widget = instance->widget;
  1019.  
  1020.   /* widget is NULL if the parent was destroyed. */
  1021.   if (widget)
  1022.     {
  1023.       Widget focus;
  1024.       Widget separator;
  1025.  
  1026.       /* Remove the destroy callback as the instance is not in the list
  1027.      anymore */
  1028.       XtRemoveCallback (instance->parent, XtNdestroyCallback,
  1029.             mark_dead_instance_destroyed,
  1030.             (XtPointer)instance);
  1031.  
  1032.       /* Give the focus to the initial item */
  1033.       focus = XtNameToWidget (widget, "*value");
  1034.       if (!focus)
  1035.     focus = XtNameToWidget (widget, "*button1");
  1036.       if (focus)
  1037.     XtSetKeyboardFocus (widget, focus);
  1038.       
  1039.       /* shrink the separator label back to their original size */
  1040.       separator = XtNameToWidget (widget, "*separator_button");
  1041.       if (separator)
  1042.     XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, 0);
  1043.  
  1044.       /* Center the dialog in its parent */
  1045.       recenter_widget (widget);
  1046.     }
  1047.   free_destroyed_instance (instance);
  1048.   return widget;
  1049. }
  1050.  
  1051. Widget
  1052. xm_create_dialog (widget_instance* instance)
  1053. {
  1054.   char*     name = instance->info->type;
  1055.   Widget     parent = instance->parent;
  1056.   Widget    widget;
  1057.   Boolean     pop_up_p = instance->pop_up_p;
  1058.   char*        shell_name = 0;
  1059.   char*     icon_name;
  1060.   Boolean    text_input_slot = False;
  1061.   Boolean    radio_box = False;
  1062.   Boolean    list = False;
  1063.   int        total_buttons;
  1064.   int        left_buttons = 0;
  1065.   int        right_buttons = 1;
  1066.   destroyed_instance*    dead_one;
  1067.  
  1068.   /* try to find a widget to recycle */
  1069.   dead_one = find_matching_instance (instance);
  1070.   if (dead_one)
  1071.     {
  1072.       Widget recycled_widget = recycle_instance (dead_one);
  1073.       if (recycled_widget)
  1074.     return recycled_widget;
  1075.     }
  1076.  
  1077.   switch (name [0]){
  1078.   case 'E': case 'e':
  1079.     icon_name = "dbox-error";
  1080.     shell_name = "Error";
  1081.     break;
  1082.  
  1083.   case 'I': case 'i':
  1084.     icon_name = "dbox-info";
  1085.     shell_name = "Information";
  1086.     break;
  1087.  
  1088.   case 'L': case 'l':
  1089.     list = True;
  1090.     icon_name = "dbox-question";
  1091.     shell_name = "Prompt";
  1092.     break;
  1093.  
  1094.   case 'P': case 'p':
  1095.     text_input_slot = True;
  1096.     icon_name = "dbox-question";
  1097.     shell_name = "Prompt";
  1098.     break;
  1099.  
  1100.   case 'Q': case 'q':
  1101.     icon_name = "dbox-question";
  1102.     shell_name = "Question";
  1103.     break;
  1104.   }
  1105.   
  1106.   total_buttons = name [1] - '0';
  1107.  
  1108.   if (name [3] == 'T' || name [3] == 't')
  1109.     {
  1110.       text_input_slot = False;
  1111.       radio_box = True;
  1112.     }
  1113.   else if (name [3])
  1114.     right_buttons = name [4] - '0';
  1115.   
  1116.   left_buttons = total_buttons - right_buttons;
  1117.   
  1118.   widget = make_dialog (name, parent, pop_up_p,
  1119.             shell_name, icon_name, text_input_slot, radio_box,
  1120.             list, left_buttons, right_buttons);
  1121.  
  1122.   XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
  1123.          (XtPointer) instance);
  1124.   return widget;
  1125. }
  1126.  
  1127. static Widget
  1128. make_menubar (widget_instance* instance)
  1129. {
  1130.   return XmCreateMenuBar (instance->parent, instance->info->name, NULL, 0);
  1131. }
  1132.  
  1133. static void
  1134. remove_grabs (Widget shell, XtPointer closure, XtPointer call_data)
  1135. {
  1136.   XmRowColumnWidget menu = (XmRowColumnWidget) closure;
  1137.   XmRemoveFromPostFromList (menu, XtParent (XtParent ((Widget) menu)));
  1138. }
  1139.  
  1140. static Widget
  1141. make_popup_menu (widget_instance* instance)
  1142. {
  1143.   Widget parent = instance->parent;
  1144.   Window parent_window = parent->core.window;
  1145.   Widget result;
  1146.  
  1147.   /* sets the parent window to 0 to fool Motif into not generating a grab */
  1148.   parent->core.window = 0;
  1149.   result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
  1150.   XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
  1151.          (XtPointer)result);
  1152.   parent->core.window = parent_window;
  1153.   return result;
  1154. }
  1155.  
  1156. /* Table of functions to create widgets */
  1157.  
  1158. #ifdef ENERGIZE
  1159.  
  1160. /* interface with the XDesigner generated functions */
  1161. typedef Widget (*widget_maker) (Widget);
  1162. extern Widget create_project_p_sheet (Widget parent);
  1163. extern Widget create_debugger_p_sheet (Widget parent);
  1164. extern Widget create_breaklist_p_sheet (Widget parent);
  1165. extern Widget create_le_browser_p_sheet (Widget parent);
  1166. extern Widget create_class_browser_p_sheet (Widget parent);
  1167. extern Widget create_call_browser_p_sheet (Widget parent);
  1168. extern Widget create_build_dialog (Widget parent);
  1169. extern Widget create_editmode_dialog (Widget parent);
  1170. extern Widget create_search_dialog (Widget parent);
  1171. extern Widget create_project_display_dialog (Widget parent);
  1172.  
  1173. static Widget
  1174. make_one (widget_instance* instance, widget_maker fn)
  1175. {
  1176.   Widget result;
  1177.   Arg     al [64];
  1178.   int     ac = 0;
  1179.  
  1180.   if (instance->pop_up_p)
  1181.     {
  1182.       XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
  1183.       result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
  1184.       XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
  1185.              (XtPointer) instance);
  1186.       (*fn) (result);
  1187.     }
  1188.   else
  1189.     {
  1190.       result = (*fn) (instance->parent);
  1191.       XtRealizeWidget (result);
  1192.     }
  1193.   return result;
  1194. }
  1195.  
  1196. static Widget
  1197. make_project_p_sheet (widget_instance* instance)
  1198. {
  1199.   return make_one (instance, create_project_p_sheet);
  1200. }
  1201.  
  1202. static Widget
  1203. make_debugger_p_sheet (widget_instance* instance)
  1204. {
  1205.   return make_one (instance, create_debugger_p_sheet);
  1206. }
  1207.  
  1208. static Widget
  1209. make_breaklist_p_sheet (widget_instance* instance)
  1210. {
  1211.   return make_one (instance, create_breaklist_p_sheet);
  1212. }
  1213.  
  1214. static Widget
  1215. make_le_browser_p_sheet (widget_instance* instance)
  1216. {
  1217.   return make_one (instance, create_le_browser_p_sheet);
  1218. }
  1219.  
  1220. static Widget
  1221. make_class_browser_p_sheet (widget_instance* instance)
  1222. {
  1223.   return make_one (instance, create_class_browser_p_sheet);
  1224. }
  1225.  
  1226. static Widget
  1227. make_call_browser_p_sheet (widget_instance* instance)
  1228. {
  1229.   return make_one (instance, create_call_browser_p_sheet);
  1230. }
  1231.  
  1232. static Widget
  1233. make_build_dialog (widget_instance* instance)
  1234. {
  1235.   return make_one (instance, create_build_dialog);
  1236. }
  1237.  
  1238. static Widget
  1239. make_editmode_dialog (widget_instance* instance)
  1240. {
  1241.   return make_one (instance, create_editmode_dialog);
  1242. }
  1243.  
  1244. static Widget
  1245. make_search_dialog (widget_instance* instance)
  1246. {
  1247.   return make_one (instance, create_search_dialog);
  1248. }
  1249.  
  1250. static Widget
  1251. make_project_display_dialog (widget_instance* instance)
  1252. {
  1253.   return make_one (instance, create_project_display_dialog);
  1254. }
  1255.  
  1256. #endif /* ENERGIZE */
  1257.  
  1258. widget_creation_entry
  1259. xm_creation_table [] = 
  1260. {
  1261.   {"menubar",             make_menubar},
  1262.   {"popup",            make_popup_menu},
  1263. #ifdef ENERGIZE
  1264.   {"project_p_sheet",        make_project_p_sheet},
  1265.   {"debugger_p_sheet",        make_debugger_p_sheet},
  1266.   {"breaklist_psheet",        make_breaklist_p_sheet},
  1267.   {"leb_psheet",               make_le_browser_p_sheet},
  1268.   {"class_browser_psheet",    make_class_browser_p_sheet},
  1269.   {"ctree_browser_psheet",    make_call_browser_p_sheet},
  1270.   {"build",            make_build_dialog},
  1271.   {"editmode",            make_editmode_dialog},
  1272.   {"search",            make_search_dialog},
  1273.   {"project_display",        make_project_display_dialog},
  1274. #endif /* ENERGIZE */
  1275.   {NULL, NULL}
  1276. };
  1277.  
  1278. /* Destruction of instances */
  1279. void
  1280. xm_destroy_instance (widget_instance* instance)
  1281. {
  1282.   Widget widget = instance->widget;
  1283.   /* recycle the dialog boxes */
  1284.   /* Disable the recycling until we can find a way to have the dialog box
  1285.      get reasonable layout after we modify its contents. */
  1286.   if (0
  1287.       && XtClass (widget) == xmDialogShellWidgetClass)
  1288.     {
  1289.       destroyed_instance* dead_instance =
  1290.     make_destroyed_instance (instance->info->name,
  1291.                  instance->info->type,
  1292.                  instance->widget,
  1293.                  instance->parent,
  1294.                  instance->pop_up_p);
  1295.       dead_instance->next = all_destroyed_instances;
  1296.       all_destroyed_instances = dead_instance;
  1297.       XtUnmanageChild (first_child (instance->widget));
  1298.       XFlush (XtDisplay (instance->widget));
  1299.       XtAddCallback (instance->parent, XtNdestroyCallback,
  1300.              mark_dead_instance_destroyed, (XtPointer)dead_instance);
  1301.     }
  1302.   else
  1303.     {
  1304.       /* This might not be necessary now that the nosel is attached to
  1305.      popdown instead of destroy, but it can't hurt. */
  1306.       XtRemoveCallback (instance->widget, XtNdestroyCallback,
  1307.             xm_nosel_callback, (XtPointer)instance);
  1308.       XtDestroyWidget (instance->widget);
  1309.     }
  1310. }
  1311.  
  1312. /* popup utility */
  1313. void
  1314. xm_popup_menu (Widget widget)
  1315. {
  1316.   XButtonPressedEvent dummy;
  1317.   XEvent* event;
  1318.  
  1319.   dummy.type = ButtonPress;
  1320.   dummy.serial = 0;
  1321.   dummy.send_event = 0;
  1322.   dummy.display = XtDisplay (widget);
  1323.   dummy.window = XtWindow (XtParent (widget));
  1324.   dummy.time = 0;
  1325.   dummy.button = 0;
  1326.   XQueryPointer (dummy.display, dummy.window, &dummy.root,
  1327.          &dummy.subwindow, &dummy.x_root, &dummy.y_root,
  1328.          &dummy.x, &dummy.y, &dummy.state);
  1329.   event = (XEvent *) &dummy;
  1330.  
  1331.   if (event->type == ButtonPress || event->type == ButtonRelease)
  1332.     {
  1333.       /* This is so totally ridiculous: there's NO WAY to tell Motif
  1334.      that *any* button can select a menu item.  Only one button
  1335.      can have that honor.
  1336.        */
  1337.       char *trans = 0;
  1338.       if      (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
  1339.       else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
  1340.       else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
  1341.       else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
  1342.       else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
  1343.       if (trans) XtVaSetValues (widget, XmNmenuPost, trans, 0);
  1344.       XmMenuPosition (widget, (XButtonPressedEvent *) event);
  1345.     }
  1346.   XtManageChild (widget);
  1347. }
  1348.  
  1349. static void
  1350. set_min_dialog_size (Widget w)
  1351. {
  1352.   short width;
  1353.   short height;
  1354.   XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, 0);
  1355.   XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, 0);
  1356. }
  1357.  
  1358. void
  1359. xm_pop_instance (widget_instance* instance, Boolean up)
  1360. {
  1361.   Widget widget = instance->widget;
  1362.  
  1363.   if (XtClass (widget) == xmDialogShellWidgetClass)
  1364.     {
  1365.       Widget widget_to_manage = first_child (widget);
  1366.       if (up)
  1367.     {
  1368.       XtManageChild (widget_to_manage);
  1369.       set_min_dialog_size (widget);
  1370.       XtSetKeyboardFocus (instance->parent, widget);
  1371.     }
  1372.       else
  1373.     XtUnmanageChild (widget_to_manage);
  1374.     }
  1375.   else
  1376.     {
  1377.       if (up)
  1378.     XtManageChild (widget);
  1379.       else
  1380.     XtUnmanageChild (widget);    
  1381.     }
  1382. }
  1383.  
  1384.  
  1385. /* motif callback */ 
  1386.  
  1387. enum do_call_type { pre_activate, selection, no_selection, post_activate };
  1388.  
  1389. static void
  1390. do_call (Widget widget, XtPointer closure, enum do_call_type type)
  1391. {
  1392.   Arg al [256];
  1393.   int ac;
  1394.   XtPointer user_data;
  1395.   widget_instance* instance = (widget_instance*)closure;
  1396.   Widget instance_widget;
  1397.   LWLIB_ID id;
  1398.  
  1399.   if (!instance)
  1400.     return;
  1401.   if (widget->core.being_destroyed)
  1402.     return;
  1403.  
  1404.   instance_widget = instance->widget;
  1405.   if (!instance_widget)
  1406.     return;
  1407.  
  1408.   id = instance->info->id;
  1409.   ac = 0;
  1410.   user_data = NULL;
  1411.   XtSetArg (al [ac], XmNuserData, &user_data); ac++;
  1412.   XtGetValues (widget, al, ac);
  1413.   switch (type)
  1414.     {
  1415.     case pre_activate:
  1416.       if (instance->info->pre_activate_cb)
  1417.     instance->info->pre_activate_cb (widget, id, user_data);
  1418.       break;
  1419.     case selection:
  1420.       if (instance->info->selection_cb)
  1421.     instance->info->selection_cb (widget, id, user_data);
  1422.       break;
  1423.     case no_selection:
  1424.       if (instance->info->selection_cb)
  1425.     instance->info->selection_cb (widget, id, (XtPointer) -1);
  1426.       break;
  1427.     case post_activate:
  1428.       if (instance->info->post_activate_cb)
  1429.     instance->info->post_activate_cb (widget, id, user_data);
  1430.       break;
  1431.     default:
  1432.       abort ();
  1433.     }
  1434. }
  1435.  
  1436. /* Like lw_internal_update_other_instances except that it does not do
  1437.    anything if its shell parent is not managed.  This is to protect 
  1438.    lw_internal_update_other_instances to dereference freed memory
  1439.    if the widget was ``destroyed'' by caching it in the all_destroyed_instances
  1440.    list */
  1441. static void
  1442. xm_internal_update_other_instances (Widget widget, XtPointer closure,
  1443.                     XtPointer call_data)
  1444. {
  1445.   Widget parent;
  1446.   for (parent = widget; parent; parent = XtParent (parent))
  1447.     if (XtIsShell (parent))
  1448.       break;
  1449.     else if (!XtIsManaged (parent))
  1450.       return;
  1451.    lw_internal_update_other_instances (widget, closure, call_data);
  1452. }
  1453.  
  1454. static void
  1455. xm_generic_callback (Widget widget, XtPointer closure, XtPointer call_data)
  1456. {
  1457.   lw_internal_update_other_instances (widget, closure, call_data);
  1458.   do_call (widget, closure, selection);
  1459. }
  1460.  
  1461. static void
  1462. xm_nosel_callback (Widget widget, XtPointer closure, XtPointer call_data)
  1463. {
  1464.   /* This callback is only called when a dialog box is dismissed with the wm's
  1465.      destroy button (WM_DELETE_WINDOW.)  We want the dialog box to be destroyed
  1466.      in that case, not just unmapped, so that it releases its keyboard grabs.
  1467.      But there are problems with running our callbacks while the widget is in
  1468.      the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
  1469.      instead of XmDESTROY and then destroy it ourself after having run the
  1470.      callback.
  1471.    */
  1472.   do_call (widget, closure, no_selection);
  1473.   XtDestroyWidget (widget);
  1474. }
  1475.  
  1476. static void
  1477. xm_pull_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
  1478. {
  1479.   do_call (widget, closure, pre_activate);
  1480. }
  1481.  
  1482. static void
  1483. xm_pop_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
  1484. {
  1485.   do_call (widget, closure, post_activate);
  1486. }
  1487.  
  1488.  
  1489. /* set the keyboard focus */
  1490. void
  1491. xm_set_keyboard_focus (Widget parent, Widget w)
  1492. {
  1493.   XmProcessTraversal (w, 0);
  1494.   XtSetKeyboardFocus (parent, w);
  1495. }
  1496.